package utils

import (
	"bufio"
	"fmt"
	"github.com/duke-git/lancet/v2/fileutil"
	"log"
	"log/slog"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"
	"video2m3u8/setting/oss"
)

// GetWorkDir 获取当前工作目录
func GetWorkDir() string {
	// 获取可执行文件的完整路径
	exePath, err := os.Getwd()
	if err != nil {
		log.Fatal(err)
	}
	return exePath
}

// StartVideo2M3u8
// ffmPeg -i vue.mp4 -c:v libx264 -hls_time 20 -hls_list_size 0 -c:a aac -strict -2 -f hls vue.m3u8
// ffmPeg能解析的格式：（asx，asf，mpg，wmv，3gp，mp4，mov，avi，flv等）
func StartVideo2M3u8(ffmpegPath string, videoPath string, m3u8Dir string, logChan chan string) {
	start := time.Now()
	logChan <- "开始转码"
	fileName := filepath.Base(videoPath)
	fileNameWithoutExt := strings.TrimSuffix(fileName, filepath.Ext(fileName))
	m3u8Path := filepath.Join(m3u8Dir, fileNameWithoutExt, "index.m3u8")
	if !fileutil.IsExist(m3u8Path) {
		err := fileutil.CreateDir(filepath.Join(m3u8Dir, fileNameWithoutExt))
		if err != nil {
			logChan <- fmt.Sprintf("创建输出文件%s失败: %v", m3u8Path, err)
			return
		}
	}
	cmd := exec.Command(ffmpegPath,
		"-i", videoPath,
		"-c:v", "libx264",
		"-b:v", "1M",
		"-hls_time", "15",
		"-hls_list_size", "0",
		"-c:a", "aac",
		"-ar", "44100",
		"-ab", "128k",
		"-strict", "-2",
		"-f", "hls",
		m3u8Path)
	logChan <- fmt.Sprintf("转码命令：%s", cmd.String())
	slog.Info("转码命令:", cmd.String())
	stdout, err := cmd.StdoutPipe()
	defer stdout.Close()
	if err != nil {
		logChan <- fmt.Sprintf("创建输出管道失败: %v", err)
		return
	}
	stderr, err := cmd.StderrPipe()
	defer stderr.Close()
	if err != nil {
		logChan <- fmt.Sprintf("创建错误管道失败: %v", err)
		return
	}
	if err := cmd.Start(); err != nil {
		logChan <- fmt.Sprintf("启动命令失败: %v", err)
		return
	}
	go func() {
		scanner := bufio.NewScanner(stdout)
		slog.Info("开始读取[stdout]日志输出")
		for scanner.Scan() {
			line := scanner.Text()
			logChan <- fmt.Sprintf(" ERROR: %s", strings.TrimSpace(line))
		}
		slog.Info("结束读取[stdout]日志输出")
	}()
	go func() {
		scanner := bufio.NewScanner(stderr)
		slog.Info("开始读取[stderr]日志输出")
		for scanner.Scan() {
			line := scanner.Text()
			logChan <- fmt.Sprintf(" INFO: %s", strings.TrimSpace(line))
		}
		slog.Info("结束读取[stderr]日志输出")
	}()
	if err := cmd.Wait(); err != nil {
		logChan <- fmt.Sprintf("(cmd.Wait())命令执行失败: %v", err)
		return
	}
	logChan <- fmt.Sprintf("执行完成,耗时:%vs", time.Since(start).Seconds())
	//文件上传oss
	uploadOss(m3u8Path, logChan)
}

func uploadOss(m3u8Path string, logChan chan string) {
	conf := oss.ReadOssConfig()
	_, buket, err := oss.GetOssClient(conf)
	if err != nil {
		logChan <- fmt.Sprintf("获取oss客户端失败,请手动上传到OSS: %v", err)
		return
	}
	tsDir := filepath.Dir(m3u8Path)
	names, err := fileutil.ListFileNames(tsDir)
	if err != nil {
		logChan <- fmt.Sprintf("获取ts文件列表失败: %v", err)
		return
	}
	mainUrl := fmt.Sprintf("%s/%s", conf.Domain, uploadKey(m3u8Path))
	logChan <- fmt.Sprintf("开始上传文件到oss，数量：【%d】,目录: %s", len(names), tsDir)
	for index, name := range names {
		//绝对路径
		path := filepath.Join(tsDir, name)
		urlKey := uploadKey(path)
		err = buket.PutObjectFromFile(urlKey, path)
		if err != nil {
			logChan <- fmt.Sprintf("上传文件{%s}失败: %v, 请手动上传到OSS", path, err)
			return
		}
		logChan <- fmt.Sprintf("上传文件{%s}成功,进度: %d/%d", path, index+1, len(names))
	}
	logChan <- fmt.Sprintf("上传文件到oss成功,目录: %s,访问路径: %s", tsDir, mainUrl)
	oss.SettingFileUrlShow(mainUrl)
}

func uploadKey(file string) string {
	filename := filepath.Base(file)
	parentDir := filepath.Dir(file)
	parentDirName := filepath.Base(parentDir)
	url := fmt.Sprintf("%s/%s", time.Now().Format("20060102"), fmt.Sprintf("%s/%s", parentDirName, filename))
	return url
}
